package com.raven.craft.code.generator.project.testcase;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.raven.craft.code.generator.project.testcase.vo.Arg;
import com.raven.craft.code.generator.project.testcase.vo.ArgConstraint;
import com.raven.craft.code.generator.project.testcase.vo.Scenario;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Getter
@Setter
@ToString
public class TestCaseVo {

    public String targetPackage;
    public String name;

    private List<Scenario> scenarios;

    private Set<String> imports;

    public TestCaseVo(TestCaseProperties testCaseProperties) {
        this.targetPackage = testCaseProperties.getTargetPackage();
        this.name = testCaseProperties.getName();
        this.scenarios = generateScenarios(testCaseProperties.getArgConstraints());
        this.imports = generateImportTypeSet();
    }

    private List<Scenario> generateScenarios(List<ArgConstraint> argConstraints) {
        // 参数搭配组合数量
        int comboCount = argConstraints
                .stream().map(e -> e.getValues().size())
                .reduce((acc, other) -> acc * other)
                .orElse(0);

        // 计算变化率
        // 变化率: 每个参数出现多少次后, 再换成另外一个值
        // 每一列的变化率 是后几列参数值数量的乘积
        int tempFrequency = comboCount;
        List<Integer> frequencies = Lists.newArrayList();
        for (ArgConstraint argConstraint : argConstraints) {
            tempFrequency /= argConstraint.getValues().size();
            frequencies.add(tempFrequency);
        }

        return IntStream.range(0, comboCount).boxed().map(index -> {

            List<Arg> args = IntStream.range(0, argConstraints.size()).boxed().map(argIndex -> {
                ArgConstraint argConstraint = argConstraints.get(argIndex);
                int frequency = frequencies.get(argIndex);
                int argValIndex = (index / frequency) % argConstraint.getValues().size();
                return new Arg(argConstraint.getName(), argConstraint.getValues().get(argValIndex));
            }).collect(Collectors.toList());
            String scenarioDesc = args.stream().map(arg -> arg.getName() + "_is_" + arg.getValue().toString().replaceAll("\\s", "_")
            ).collect(Collectors.joining("_and_"));

            return new Scenario(scenarioDesc, args);
        }).collect(Collectors.toList());
    }

    private Set<String> generateImportTypeSet() {
        Set<String> set = Sets.newHashSet();

        set.add("org.junit.jupiter.api.Test");
        set.add("org.springframework.boot.test.context.SpringBootTest");

        return set;
    }
}
